/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package team11;

/**
 *
 * 遗传算法优化器 使用遗传算法优化神经网络参数，支持自适应变异和锦标赛选择
 *
 * @author 朱婧雯
 */
import java.util.*;

public class GeneticAlgorithm {

    private Random random;
    private int populationSize;
    private double mutationRate;
    private double crossoverRate;
    private int elitismCount;
    private double initialMutationRate;
    private boolean adaptiveMutation = true;

    /**
     * 遗传算法构造函数
     *
     * @param populationSize
     * @param mutationRate
     * @param crossoverRate
     * @param elitismCount
     */
    public GeneticAlgorithm(int populationSize, double mutationRate, double crossoverRate, int elitismCount) {
        if (populationSize <= 0) {
            throw new IllegalArgumentException("种群大小必须大于0");
        }
        if (mutationRate < 0 || mutationRate > 1) {
            throw new IllegalArgumentException("变异率必须在[0,1]范围内");
        }
        if (crossoverRate < 0 || crossoverRate > 1) {
            throw new IllegalArgumentException("交叉率必须在[0,1]范围内");
        }
        if (elitismCount < 0 || elitismCount >= populationSize) {
            throw new IllegalArgumentException("精英保留数量必须在[0,种群大小)范围内");
        }

        this.random = new Random();
        this.populationSize = populationSize;
        this.mutationRate = mutationRate;
        this.crossoverRate = crossoverRate;
        this.elitismCount = elitismCount;
        this.initialMutationRate = mutationRate;
    }

    /**
     * 个体类，表示遗传算法中的一个解
     */
    public static class Individual {

        public double[] chromosome;
        public double fitness;
        public double error;

        public Individual(int chromosomeLength) {
            this.chromosome = new double[chromosomeLength];
            this.fitness = 0;
            this.error = Double.MAX_VALUE;
        }

        public Individual(double[] chromosome) {
            this.chromosome = chromosome;
            this.fitness = 0;
            this.error = Double.MAX_VALUE;
        }
    }

    /**
     * 使用遗传算法训练神经网络
     *
     * @param network
     * @param inputs
     * @param targets
     * @param generations
     */
    public void train(NeuralNetwork network, double[][] inputs, double[][] targets, int generations) {
        if (network == null) {
            throw new IllegalArgumentException("神经网络不能为null");
        }
        if (inputs == null || targets == null) {
            throw new IllegalArgumentException("输入数据和目标数据不能为null");
        }
        if (inputs.length != targets.length) {
            throw new IllegalArgumentException("输入数据和目标数据数量不匹配");
        }
        if (generations <= 0) {
            throw new IllegalArgumentException("进化代数必须大于0");
        }

        System.out.println("开始遗传算法训练...");
        System.out.println("种群大小: " + populationSize + ", 代数: " + generations);

        int chromosomeLength = network.getTotalParameters();
        List<Individual> population = initializePopulation(chromosomeLength);

        Individual bestIndividual = null;
        double bestFitnessHistory = -1;

        for (int gen = 0; gen < generations; gen++) {
            evaluatePopulation(population, network, inputs, targets);
            bestIndividual = getBestIndividual(population);

            List<Individual> newPopulation = new ArrayList<>();

            // 精英保留
            for (int i = 0; i < elitismCount && i < population.size(); i++) {
                newPopulation.add(new Individual(Arrays.copyOf(population.get(i).chromosome, chromosomeLength)));
            }

            // 生成新个体
            while (newPopulation.size() < populationSize) {
                Individual parent1 = tournamentSelection(population, 3);
                Individual parent2 = tournamentSelection(population, 3);
                Individual child = uniformCrossover(parent1, parent2);
                adaptiveMutate(child, gen, generations);
                newPopulation.add(child);
            }

            population = newPopulation;

            // 记录最佳适应度历史
            if (bestIndividual.fitness > bestFitnessHistory) {
                bestFitnessHistory = bestIndividual.fitness;
            }

            if (gen % 10 == 0) {
                System.out.printf("第 %d 代, 最佳适应度: %.6f, 误差: %.6f%n",
                        gen, bestIndividual.fitness, bestIndividual.error);
            }
        }

        network.setAllParameters(bestIndividual.chromosome);

        System.out.println("遗传算法训练完成!");
        System.out.printf("最终适应度: %.6f, 最终误差: %.6f%n",
                bestIndividual.fitness, bestIndividual.error);
    }

    /**
     * 初始化种群
     */
    private List<Individual> initializePopulation(int chromosomeLength) {
        List<Individual> population = new ArrayList<>();

        for (int i = 0; i < populationSize; i++) {
            Individual individual = new Individual(chromosomeLength);
            for (int j = 0; j < chromosomeLength; j++) {
                // 使用Xavier初始化
                individual.chromosome[j] = random.nextGaussian() * Math.sqrt(2.0 / chromosomeLength);
            }
            population.add(individual);
        }

        return population;
    }

    /**
     * 改进的适应度评估 - 使用排名选择
     */
    private void evaluatePopulation(List<Individual> population, NeuralNetwork network,
            double[][] inputs, double[][] targets) {
        for (Individual individual : population) {
            network.setAllParameters(individual.chromosome);
            double error = calculateMSE(network, inputs, targets);
            individual.error = error;
        }

        // 按误差升序排序（误差小的排在前面）
        population.sort((a, b) -> Double.compare(a.error, b.error));

        // 使用排名适应度
        for (int i = 0; i < population.size(); i++) {
            double rankFitness = (population.size() - i) / (double) population.size();
            population.get(i).fitness = rankFitness;
        }
    }

    /**
     * 计算均方误差
     */
    private double calculateMSE(NeuralNetwork network, double[][] inputs, double[][] targets) {
        double totalError = 0;

        for (int i = 0; i < inputs.length; i++) {
            double[] output = network.forward(inputs[i]);
            for (int j = 0; j < output.length; j++) {
                totalError += Math.pow(output[j] - targets[i][j], 2);
            }
        }

        return totalError / inputs.length;
    }

    /**
     * 获取最佳个体
     */
    private Individual getBestIndividual(List<Individual> population) {
        return population.get(0);
    }

    /**
     * 锦标赛选择
     */
    private Individual tournamentSelection(List<Individual> population, int tournamentSize) {
        Individual best = null;

        for (int i = 0; i < tournamentSize; i++) {
            Individual candidate = population.get(random.nextInt(population.size()));
            if (best == null || candidate.fitness > best.fitness) {
                best = candidate;
            }
        }

        return best;
    }

    /**
     * 均匀交叉
     */
    private Individual uniformCrossover(Individual parent1, Individual parent2) {
        if (random.nextDouble() > crossoverRate) {
            return new Individual(Arrays.copyOf(parent1.chromosome, parent1.chromosome.length));
        }

        Individual child = new Individual(parent1.chromosome.length);

        for (int i = 0; i < parent1.chromosome.length; i++) {
            if (random.nextBoolean()) {
                child.chromosome[i] = parent1.chromosome[i];
            } else {
                child.chromosome[i] = parent2.chromosome[i];
            }
        }

        return child;
    }

    /**
     * 自适应变异
     */
    private void adaptiveMutate(Individual individual, int generation, int maxGenerations) {
        double currentMutationRate = mutationRate;

        if (adaptiveMutation) {
            double decayFactor = 1.0 - (generation / (double) maxGenerations);
            currentMutationRate = initialMutationRate * decayFactor;
            currentMutationRate = Math.max(currentMutationRate, 0.01);
        }

        for (int i = 0; i < individual.chromosome.length; i++) {
            if (random.nextDouble() < currentMutationRate) {
                double range = 1.0 - Math.abs(individual.chromosome[i]);
                individual.chromosome[i] += random.nextGaussian() * range * 0.5;
                individual.chromosome[i] = Math.max(-1, Math.min(1, individual.chromosome[i]));
            }
        }
    }

    // 设置自适应变异
    public void setAdaptiveMutation(boolean adaptiveMutation) {
        this.adaptiveMutation = adaptiveMutation;
    }
}
